package cn.biplam.back.sql.ddl;

import java.io.Serializable;

import cn.biplam.back.sql.type.Type;
import cn.biplam.common.wrapper.ErrorMessage;

/**
 * 提供字段的语义模型
 * <ul>字段的属性有：
 *  <li>物理名称
 *  <li>逻辑名称
 *  <li>数据类型
 *  <li>字段描述
 *  <li>是否允许空值
 *  <li>字段默认值
 *  </ul>
 * @author 	WangSong Mar 11, 2009 7:17:49 PM
 * @version 1.0
 */
public class Field implements Serializable{

	/**允许Null*/
	public static final boolean ALLOW_NULL=true;
	/**不允许Null*/
	public static final boolean NOT_NULL=false;
	private static final int COLUMN_NAME_LENGTH=50;
	private static final long serialVersionUID = -2973969433014295388L;
	
	/**是否允许字段值为NULL*/
	private boolean bIsNull=true;
	private Default mDefault=null;
	
	/**字段的数据类型*/
	private Type mType=null;
	/**字段描述*/
	private String sComment=null;
	/**字段物理名称*/
	private String sPhisicalName=null;
	/** 字段逻辑名称 */
	private String sLogicName = null;

	/**
	 * 构造方法	 传入 名称、数据类型、Null标志 初始化
	 * @param sName		字段名称
	 * @param mType		字段数据元
	 * @param isNull	Null标志(true=允许为空,false=Not Null)
	 * @throws ErrorMessage
	 */
	public Field(String sName,String sComment,Type mType, boolean isNull) throws ErrorMessage {
		this(sName,sComment,mType,null,isNull);
	}

	/**
	 * 构造方法	 传入 名称、数据类型、默认值、Null标志 初始化
	 * @param sName		字段名称
	 * @param mType		字段数据元
	 * @param mDefault	字段默认值
	 * @param isNull	Null标志(true=允许为空,false=Not Null)
	 * @throws ErrorMessage
	 */
	public Field(String sName,String sComment,Type mType, Default mDefault,boolean isNull) throws ErrorMessage {
		this(sName,null,sComment,mType,mDefault,isNull);
	}

	/**
	 * 	创建字段
	 * @param sPhicicalName 物理名称
	 * @param sLogicName    逻辑名称 
	 * @param sComment      说明
	 * @param mType         数据类型
	 * @param mDefault      默认值
	 * @param isNull        是否为空
	 * @throws ErrorMessage
	 */
	public Field(String sPhicicalName,String sLogicName ,String sComment,Type mType, Default mDefault,boolean isNull) throws ErrorMessage{
		this.setPhisicalName(sPhicicalName);
		this.setLogicName(sLogicName);
		this.setType(mType);
		if(mDefault!=null && !"-1".equals(mDefault.toString())){
			this.setDefault(mDefault);
		}
		this.setNull(isNull);
		this.sComment = sComment;
	}
	
	/**
	 * 构造方法 传入 名称、数据类型 初始化
	 * @param sName	字段名称
	 * @param mType 字段数据元
	 * @throws ErrorMessage
	 */
	public Field(String sName,Type mType) throws ErrorMessage{
		this(sName,null,mType,null,true);
	}
	
	/**
	 * 创建字段
	 * @param sPhicicalName 物理名称
	 * @param sLogicName    逻辑名称
	 * @param sComment      说明 
	 * @param mType         数据类型
	 * @param isNull        是否为空
	 * @throws ErrorMessage
	 */
	public Field(String sPhicicalName,String sLogicName ,String sComment,Type mType,boolean isNull) throws ErrorMessage{
		this(sPhicicalName,sLogicName,sComment,mType,null,isNull);
	}

	/**
	 * 构造方法	 传入 名称、数据类型、默认值 初始化
	 * @param sName		字段名称
	 * @param mType		字段数据元
	 * @param mDefault	字段默认值
	 * @throws ErrorMessage
	 */
	public Field(String sName,Type mType, Default mDefault) throws ErrorMessage {
		this(sName,null,mType,mDefault,true);
	}
	
	/**
	 * 检查字段名称是否符合规范
	 * @param sName
	 * @return true/false
	 * @throws ErrorMessage
	 */
	private boolean checkName(String sName) throws ErrorMessage{

		ErrorMessage eMsg=null;

		if(sName==null){
			eMsg=new ErrorMessage("Columne Name is null!");
		}else if(sName.length()>COLUMN_NAME_LENGTH){
			StringBuilder sb = new StringBuilder();
			sb.append("Column name length(");
			sb.append(sName.length());
			sb.append(") is too long!");
			eMsg=new ErrorMessage(sb.toString());
		}

		if(eMsg==null){
			return true;
		}else{
			throw eMsg;
		}
	}

	/**
	 * 获取字段描述
	 * @return 字段描述
	 */
	public String getComment() {
		if(sComment!=null && "null".equals(sComment.trim())){
			sComment = null;
		}
		return this.sComment;
	}

	/**
	 * 返回SQL语法表示的该字段的默认值
	 * @return	字段默认值
	 */
	public String getDefault() {
		if(mDefault!=null){
			return mDefault.toString();
		}
		return null;
	}

	/**
	 * 获取字段逻辑名称
	 * @return 字段逻辑名
	 */
	public String getLogicName() {
		if(sLogicName!=null && "null".equals(sLogicName.trim())){
			sLogicName = null;
		}
		return this.sLogicName;
	}

	/**
	 * 返回字段名称
	 * @return 字段名称
	 */
	public String getPhisicalName() {
		if(sPhisicalName!=null && "null".equals(sPhisicalName.trim())){
			sPhisicalName = null;
		}
		return sPhisicalName.toUpperCase();
	} 

	/**
	 * 返回物理名称
	 * @return 物理名称
	 */
	public String getPhysicalName() {
		if(sPhisicalName!=null && "null".equals(sPhisicalName.trim())){
			sPhisicalName = null;
		}
		return this.sPhisicalName;
	}

	/**
	 * 返回字段类型描述
	 * @return 字段类型描述
	 */
	public Type getType() {
		return (Type)mType;
	}

	/**
	 * 返回该字段是否允许null
	 * @return true/false
	 */
	public boolean isNull() {
		return this.bIsNull;
	}

	/**
	 * 设置字段说明
	 * @param comment
	 */
	public void setComment(String comment) {
		this.sComment = comment;
	}

	/**
	 * 设置字段逻辑名称
	 * @param logicName
	 */
	public void setLogicName(String logicName) {
		this.sLogicName = logicName;
	}

	/**
	 * 设置字段的默认值
	 * @param mDefault	字段默认值对象
	 */
	public void setDefault(Default mDefault) {
		this.mDefault = mDefault;
	}

	/**
	 * 设置字段名称
	 * @param sName	字段名称
	 * @throws ErrorMessage 
	 */
	public void setPhisicalName(String sName) throws ErrorMessage {
		checkName(sName);
		this.sPhisicalName = sName;
	}

	/**
	 * 设置该字段是否允许null
	 * @param isNull	Null标志(true=允许为空,false=Not Null)
	 */
	public void setNull(boolean isNull) {
		this.bIsNull = isNull;
	}
	
	/**
	 * 设置字段的数据元
	 * @param mType	数据元
	 * @throws ErrorMessage 
	 */
	public void setType(Type mType) throws ErrorMessage {
		if(Type.class.isInstance(mType)){
			this.mType = mType;
		}else{
			StringBuilder sb = new StringBuilder();
			sb.append("The parameter type(+");
			sb.append(mType.getClass().getName());
			sb.append(" is not a valid type!");
			ErrorMessage eMsg=new ErrorMessage(sb.toString());
			throw eMsg;
		}
	}

	/**
	 * 返回SQL语法表示的字段的通用定义语句
	 * @return	SQL语法表示的字段的通用定义语句
	 */
	public String toString(){

		StringBuilder sb =new StringBuilder();

		/**名称转为大写*/
		sb.append(this.getPhisicalName());

		/**确保字段名称长度在24个字符以内的，其类型描述能对齐*/
		for(int i=sPhisicalName.length();i<24;i+=8){
			sb.append("\t");
		}

		sb.append(((Type)mType).getType());

		/**Default语句*/
		if(this.mDefault!=null){
			sb.append(" DEFAULT ");
			sb.append(this.mDefault.toString());
		}

		/**Not Null语句*/
		if(!this.bIsNull){
			sb.append(" NOT NULL ");
		}

		return sb.toString();
	}

}
